#include "OgreFramework.hpp"

using namespace Ogre;

// Initialise the Ogre singleton.
template<> OgreFramework* Ogre::Singleton<OgreFramework>::ms_Singleton = 0;

// Constructor. As per usual, use this to initialise variables.
OgreFramework::OgreFramework()
{
	m_pRoot				= 0;
	m_pRenderWnd		= 0;
	m_pViewport			= 0;
	m_pLog				= 0;
	m_pTimer			= 0;
	
	m_pInputMgr			= 0;
	m_pKeyboard			= 0;
	m_pMouse			= 0;

	m_pTrayMgr			= 0;

	m_bIsOverlayEnabled = false;
}

// Destructor. Clean up the mess in the destructor.
OgreFramework::~OgreFramework()
{
	// Log that Ogre is shutting down.
	OgreFramework::getSingletonPtr()->m_pLog->logMessage("Shutdown OGRE...");

	// Free up the memory used by our big pointer objects.
	if (m_pTrayMgr)
		delete m_pTrayMgr;
	if (m_pInputMgr)
		OIS::InputManager::destroyInputSystem(m_pInputMgr);
	if (m_pRoot)
		delete m_pRoot;
}

// Powers up Ogre by doing these things:
// 1. Create the log manager.
// 2. Create the Root.
// 3. Create the RenderWindow and its Viewport.
// 4. Power up OIS.
// 5. If a Mouse/Keyboard Listener was not passed in, use the default ones.
// 6. Load the Resources.
// 7. Start up SDKTrays.
// 8. Start the Timer.
// 9. Create and display the debug overlay.
bool OgreFramework::initOgre(Ogre::String wndTitle, OIS::KeyListener *pKeyListener, OIS::MouseListener *pMouseListener)
{
	//=========================================================================
	// 1. Create the log manager.
	//=========================================================================
	Ogre::LogManager* logMgr = new Ogre::LogManager();

	// Create the log manager singleton. 
	m_pLog = Ogre::LogManager::getSingleton().createLog("OgreLogfile.log", true, true, false);
	m_pLog->setDebugOutputEnabled(true);

	//=========================================================================
	// 2. Create the Root.
	//=========================================================================
	m_pRoot = new Ogre::Root();

	// Show the config dialog box. 
	if (!m_pRoot->showConfigDialog())
		return false;

	//=========================================================================
	// 3. Create the RenderWindow and its Viewport.
	//=========================================================================
	m_pRenderWnd = m_pRoot->initialise(true, wndTitle);
	
	// Add the viewport to the RenderWindow and set the background color.
	m_pViewport = m_pRenderWnd->addViewport(0);
	m_pViewport->setBackgroundColour(ColourValue(0.25, 0.25f, 0.25f));
	m_pViewport->setCamera(0);

	//=========================================================================
	// 4. Power up OIS.
	//=========================================================================

	// Get the name of the window and give it to OIS.
	unsigned long hWnd = 0;
	OIS::ParamList paramList;
	m_pRenderWnd->getCustomAttribute("WINDOW", &hWnd);
	paramList.insert(OIS::ParamList::value_type("WINDOW", Ogre::StringConverter::toString(hWnd)));
	
	// Create input system.
	m_pInputMgr = OIS::InputManager::createInputSystem(paramList);
	
	// Create the Keyboard and Mouse objects
	m_pKeyboard = static_cast<OIS::Keyboard*>(m_pInputMgr->createInputObject(OIS::OISKeyboard, true));
	m_pMouse = static_cast<OIS::Mouse*>(m_pInputMgr->createInputObject(OIS::OISMouse, true));

	// Set the mouse to the RenderWindow's size.
	m_pMouse->getMouseState().height = m_pRenderWnd->getHeight();
	m_pMouse->getMouseState().width = m_pRenderWnd->getWidth();

	//=========================================================================
	// 5. If a Mouse/Keyboard Listener was not passed in, use the default ones.
	//=========================================================================

	if (pKeyListener == 0)
		m_pKeyboard->setEventCallback(this);
	else
		m_pKeyboard->setEventCallback(pKeyListener);

	if (pMouseListener == 0)
		m_pMouse->setEventCallback(this);
	else
		m_pMouse->setEventCallback(pMouseListener);

	//=========================================================================
	// 6. Load the Resources.
	//=========================================================================

	// Note the resources.cfg here.
	Ogre::String secName, typeName, archName;
    Ogre::ConfigFile cf;
    cf.load("resources.cfg");
 
	// Fills out the ResourceGroupManager with the stuff in the config files.
    Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
    while (seci.hasMoreElements())
    {
        secName = seci.peekNextKey();
        Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
        Ogre::ConfigFile::SettingsMultiMap::iterator i;
        for (i = settings->begin(); i != settings->end(); ++i)
        {
            typeName = i->first;
            archName = i->second;
            Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
        }
    }

	// Initialise all the resource groups. 
    Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

	//=========================================================================
	// 7. Start up SDKTrays
	//=========================================================================

	// Start up SDKTrays and hide the cursor by default.
	m_pTrayMgr = new OgreBites::SdkTrayManager("FrameworkInterface", m_pRenderWnd, m_pMouse, this);
	m_pTrayMgr->hideCursor();

	//=========================================================================
	// 8. Start the Timer.
	//=========================================================================

	m_pTimer = new Ogre::Timer();
	m_pTimer->reset();

	//=========================================================================
	// 9. Create the display.
	//=========================================================================
	
	m_pRenderWnd->setActive(true);

	return true;
}

// This is called once per frame by the AppStateManager to update everything
// directly related to Ogre. All updates are taken care of by the application
// states, but if some central task needs to be done, it could be done here.
void OgreFramework::updateOgre(double timeSinceLastFrame)
{
}

// Override for the keyPressed from the OIS. This is going to set up a couple
// simple commands to control our window.
bool OgreFramework::keyPressed(const OIS::KeyEvent& keyEventRef)
{
	// Take a screenshot on print screen key.
	if (m_pKeyboard->isKeyDown(OIS::KC_SYSRQ))
	{
		m_pRenderWnd->writeContentsToTimestampedFile("Screenshot_", ".jpg");
		return true;
	}

	// Show/hide the debug overlay stuff with O.
	if (m_pKeyboard->isKeyDown(OIS::KC_O))
	{
		if (m_bIsOverlayEnabled)
		{
			m_pTrayMgr->hideFrameStats();
			m_bIsOverlayEnabled = false;
			return true;
		}
		else
		{
			m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);
			m_bIsOverlayEnabled = true;
			return true;
		}
	}

	return true;
}

// For the moment, these are unused, but they need to be here because of the
// OIS being used and overriden.
 
bool OgreFramework::keyReleased(const OIS::KeyEvent &keyEventRef)
{
    return true;
}
 
bool OgreFramework::mouseMoved(const OIS::MouseEvent &evt)
{
    return true;
}
 
bool OgreFramework::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    return true;
}
 
bool OgreFramework::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
    return true;
}